package wortubung.util;

import java.util.HashMap;
import java.util.HashSet;

//File encoding: UTF-8
public class CyrillicScript {

	private static HashMap<Character,Transliterator.Consumer> toVernacularMap =
    		new HashMap<Character,Transliterator.Consumer>();
    private static HashSet<Character> vowelSet = new HashSet<Character>();
	private static HashMap<Character,String> toLatinMap = new HashMap<Character,String>();

	// Accents won't work: а́ е́ и́ о́ у́ ы́ э́ ю́ я́  -- each is a two-character combo.
    private static final String[] cyrillicLetterInfo = {
	    "A    \u0410 А   \u0430 а    v",
	    "B    \u0411 Б   \u0431 б",
	    "V    \u0412 В   \u0432 в",
	    "G    \u0413 Г   \u0433 г",
	    "D    \u0414 Д   \u0434 д",
	    "JE   \u0415 Е   \u0435 е    v",
	    "JO   \u0401 Ё   \u0451 ё    v",
	    "ZH   \u0416 Ж   \u0436 ж",
	    "Z    \u0417 З   \u0437 з",
	    "I    \u0418 И   \u0438 и    v",
	    "J    \u0419 Й   \u0439 й    v",   // jj
	    "K    \u041A К   \u043A к",
	    "L    \u041B Л   \u043B л",
	    "M    \u041C М   \u043C м",
	    "N    \u041D Н   \u043D н",
	    "O    \u041E О   \u043E о    v",
	    "P    \u041F П   \u043F п",
	    "R    \u0420 Р   \u0440 р",
	    "S    \u0421 С   \u0441 с",
	    "T    \u0422 Т   \u0442 т",
	    "U    \u0423 У   \u0443 у",
	    "F    \u0424 Ф   \u0444 ф",
	    "X    \u0425 Х   \u0445 х",        // kh
	    "C    \u0426 Ц   \u0446 ц",
	    "CH   \u0427 Ч   \u0447 ч",
	    "SH   \u0428 Ш   \u0448 ш",
	    "SX   \u0429 Щ   \u0449 щ",        // shh
	    "\"   \u042A Ъ   \u044A ъ",
	    "Y    \u042B Ы   \u044B ы    v",
	    "'    \u042C Ь   \u044C ь",
	    "E    \u042D Э   \u044D э    v",   // eh
	    "JU   \u042E Ю   \u044E ю    v",
	    "JA   \u042F Я   \u044F я    v",
    };

	//  J    \u0419 Й   \u0439 й
	//  JE   \u0415 Е   \u0435 е
	//  JO   \u0401 Ё   \u0451 ё
	//  JU   \u042E Ю   \u044E ю
	//  JA   \u042F Я   \u044F я
    private static class ConsumerJ extends Transliterator.Consumer {
		@Override public void proceed(Transliterator t) throws TransliterateException {
			if (charAt(t) == 'j') { // lower case
				if (!consume(t, 'e', '\u0435') &&	// je
				    !consume(t, 'o', '\u0451') &&	// jo
				    !consume(t, 'u', '\u044E') &&	// ju
					!consume(t, 'a', '\u044F'))		// ja
					consume(t, '\u0439');			// j
			} else {
				if (!consume(t, 'E', '\u0415') &&	// JE
					!consume(t, 'O', '\u0401') &&	// JO
					!consume(t, 'U', '\u042E') &&	// JU
					!consume(t, 'A', '\u042F'))		// JA
					consume(t, '\u0419');			// J
			}
		}
    }

	//  Z    \u0417 З   \u0437 з
	//  ZH   \u0416 Ж   \u0436 ж
    private static class ConsumerZ extends Transliterator.Consumer {
		@Override public void proceed(Transliterator t) throws TransliterateException {
			if (charAt(t) == 'z') { // lower case
				if (!consume(t, 'h', '\u0436'))		// zh
					consume(t, '\u0437');			// z
			} else {
				if (!consume(t, 'H', '\u0416'))		// ZH
					consume(t, '\u0417');			// Z
			}
		}
    }

	//  C    \u0426 Ц   \u0446 ц"
	//  CH   \u0427 Ч   \u0447 ч"
    private static class ConsumerC extends Transliterator.Consumer {
		@Override public void proceed(Transliterator t) throws TransliterateException {
			if (charAt(t) == 'c') { // lower case
				if (!consume(t, 'h', '\u0447'))		// ch
					consume(t, '\u0446');			// c
			} else {
				if (!consume(t, 'H', '\u0427'))		// CH
					consume(t, '\u0426');			// C
			}
		}
    }

	//  S    \u0421 С   \u0441 с
	//  SH   \u0428 Ш   \u0448 ш
	//  SX   \u0429 Щ   \u0449 щ
    private static class ConsumerS extends Transliterator.Consumer {
		@Override public void proceed(Transliterator t) throws TransliterateException {
			if (charAt(t) == 's') { // lower case
				if (!consume(t, 'h', '\u0448') &&	// sh
				    !consume(t, 'x', '\u0449'))		// sx
					consume(t, '\u0441');			// s
			} else {
				if (!consume(t, 'H', '\u0428') &&	// SH
					!consume(t, 'X', '\u0429'))		// SX
					consume(t, '\u0421');			// S
			}
		}
    }

    //    '   \u042C Ь   \u044C ь
    private static class Consumer_ extends Transliterator.Consumer {
    	// Since ' does not have case, we check the next character,
    	// and use its case to determine that of the cyrillic letter.
		@Override public void proceed(Transliterator t) {
			Character la = lookahead(t);
			boolean isLowerCase = (la == null) || Character.isLowerCase(la);
			consume(t, isLowerCase ? '\u044C' : '\u042C');
		}
    }

    //    "   \u042A Ъ   \u044A ъ
    private static class Consumer__ extends Transliterator.Consumer {
    	// Since ' does not have case, we check the next character,
    	// and use its case to determine that of the cyrillic letter.
		@Override public void proceed(Transliterator t) {
			Character la = lookahead(t);
			boolean isLowerCase = (la == null) || Character.isLowerCase(la);
			consume(t, isLowerCase ? '\u044A' : '\u042A');
		}
    }

    static {
    	toVernacularMap.put('\'', new Consumer_());
    	toVernacularMap.put('"',  new Consumer__());

    	toVernacularMap.put('J',  new ConsumerJ());
    	toVernacularMap.put('Z',  new ConsumerZ());
    	toVernacularMap.put('C',  new ConsumerC());
    	toVernacularMap.put('S',  new ConsumerS());

    	toVernacularMap.put('j',  toVernacularMap.get('J'));
    	toVernacularMap.put('z',  toVernacularMap.get('Z'));
    	toVernacularMap.put('c',  toVernacularMap.get('C'));
    	toVernacularMap.put('s',  toVernacularMap.get('S'));

    	for (String infoString : cyrillicLetterInfo) {
			String[] sa = infoString.split(" +");
			String latin = sa[0];
			char upperCase = sa[1].charAt(0);
			char lowerCase = sa[3].charAt(0);
			if (sa.length == 5) { // is a vowel
				vowelSet.add(upperCase);
				vowelSet.add(lowerCase);
			}

			char c = latin.charAt(0);
			if (latin.length() == 1 && !toVernacularMap.containsKey(c)) {
				toVernacularMap.put(c, new Transliterator.OneToOneConsumer(upperCase));
				c = Character.toLowerCase(c);
				toVernacularMap.put(c, new Transliterator.OneToOneConsumer(lowerCase));
			}
    	}
	}

    public static void toCyrillic(String[] sa) throws TransliterateException {
    	if (sa != null) {
	    	for (int i=sa.length-1; i>=0; --i)
	    		sa[i] = toCyrillic(sa[i]);
    	}
    }

    public static String toCyrillic(String latinInput) throws TransliterateException {
    	return new Transliterator(toVernacularMap).getVernacular(latinInput);
    }

    public static String toLatin(char cyrillicInput) {
    	return toLatinMap.get(cyrillicInput);
    }

    public static String toLatin(String cyrillicInput) {
    	StringBuilder sb = new StringBuilder();
    	for (int i=0; i<cyrillicInput.length(); ++i)
    		sb.append(toLatin(cyrillicInput.charAt(i)));
    	return sb.toString();
    }

    public static boolean startsWithVowel(String str) {
    	return str.length() > 0 && isVowel(str.charAt(0));
    }

    public static boolean endsWithVowel(String str) {
    	return str.length() > 0 && isVowel(str.charAt(str.length()-1));
    }

    public static boolean isVowel(char ch) {
        return vowelSet.contains(ch);
    }

    public static void main(String[] args) throws Exception {
    	String fmt = "%-3s [%s] %4s [%s] %4s    [%s] %4s [%s] %4s\r\n";
    	for (String s : cyrillicLetterInfo) {
    		String[] sa = s.split(" +");
    		Console.print(String.format(fmt, sa[0],
    				sa[1], Integer.toHexString((int)sa[1].charAt(0)),
    				sa[2], Integer.toHexString((int)sa[2].charAt(0)),
    				sa[3], Integer.toHexString((int)sa[3].charAt(0)),
    				sa[4], Integer.toHexString((int)sa[4].charAt(0))));
    	}
    }
}
